﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using ProgNetComponents.Design.Attributes;

namespace ProgNetComponents.Design.TypeDescriptors
{
    /// <summary>
    /// This type description provider should be used for abstract classes
    /// Use AbstractClassReferenceAttribute to set non abstract type for abstract class
    /// </summary>
    public class AbstractClassTypeDescriptionProvider : TypeDescriptionProvider
    {
        private Type AbstractType;
        private Type RealType;
        private void GetTypes(Type t)
        {
            if (AbstractType == null)
            {
                Type searchType = t;
                while (AbstractType == null && searchType != null && searchType != typeof(Object))
                {
                    foreach (AbstractClassReferenceAttribute cca in searchType.GetCustomAttributes(typeof(AbstractClassReferenceAttribute), false))
                    {
                        AbstractType = searchType;
                        RealType = cca.ReferencedType;
                        break;
                    }
                    searchType = searchType.BaseType;
                }
            }
        }
        public AbstractClassTypeDescriptionProvider()
            : base(TypeDescriptor.GetProvider(typeof(System.Windows.Forms.Form)))
        {
            
        }

        public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
        {
            GetTypes(objectType);
            if (objectType != null && AbstractType != null && 
                objectType.FullName == AbstractType.FullName)
                objectType = RealType;
            return base.CreateInstance(provider, objectType, argTypes, args);
        }

        public override Type GetReflectionType(Type objectType, object instance)
        {
            GetTypes(objectType);
            if (objectType != null && AbstractType != null &&
                objectType.FullName == AbstractType.FullName)
                objectType = RealType;
            Type t = base.GetReflectionType(objectType, instance);
            return t;
        }
    }
}
